import json
import re
from typing import Optional, Dict, Tuple

from LlmModel.DoubaoModel.DoubaoModel import DoubaoModel
from utils.logger import get_logger

logger = get_logger(__name__)


class PromotionChecker:
    """推广周期和创作方向检查器"""

    def __init__(self):
        self.doubao_client = DoubaoModel()

    def _extract_end_date(self, period_str: str) -> str:
        """
        从推广周期字符串中提取结束日期

        :param period_str: 推广周期字符串，格式为"月.日"或"月.日-月.日"
        :return: 结束日期，格式为"月.日"
        """
        if '-' in period_str:
            # 如果是时间段，取结束时间
            return period_str.split('-')[1]
        else:
            # 如果是单个时间点，直接返回
            return period_str

    def _extract_date_parts(self, date_str: str) -> Tuple[int, int]:
        """
        从日期字符串中提取月份和日期

        :param date_str: 日期字符串，格式为"月.日"
        :return: (月份, 日期)
        """
        parts = date_str.split('.')
        if len(parts) != 2:
            raise ValueError(f"日期格式不正确: {date_str}")

        month = int(parts[0])
        day = int(parts[1])
        return month, day

    def _compare_promotion_dates(self, base_period: str, user_period: str) -> bool:
        """
        比较推广周期日期，确保user_period在base_period范围内

        :param base_period: 基础推广周期
        :param user_period: 用户表单推广周期
        :return: user_period是否在base_period范围内
        """
        try:
            # 判断base_period是时间段还是时间点
            if '-' in base_period:
                # base_period是时间段，提取开始和结束时间
                base_start_str, base_end_str = base_period.split('-')
                base_start_month, base_start_day = self._extract_date_parts(base_start_str)
                base_end_month, base_end_day = self._extract_date_parts(base_end_str)

                # 判断user_period是时间段还是时间点
                if '-' in user_period:
                    # user_period也是时间段，提取开始和结束时间
                    user_start_str, user_end_str = user_period.split('-')
                    user_start_month, user_start_day = self._extract_date_parts(user_start_str)
                    user_end_month, user_end_day = self._extract_date_parts(user_end_str)

                    # 检查user_period是否完全在base_period内
                    # 比较开始时间
                    if user_start_month < base_start_month:
                        return False
                    elif user_start_month == base_start_month and user_start_day < base_start_day:
                        return False

                    # 比较结束时间
                    if user_end_month > base_end_month:
                        return False
                    elif user_end_month == base_end_month and user_end_day > base_end_day:
                        return False

                    return True
                else:
                    # user_period是时间点，检查是否在base_period内
                    user_month, user_day = self._extract_date_parts(user_period)

                    # 检查是否在base_start之后
                    if user_month < base_start_month:
                        return False
                    elif user_month == base_start_month and user_day < base_start_day:
                        return False

                    # 检查是否在base_end之前
                    if user_month > base_end_month:
                        return False
                    elif user_month == base_end_month and user_day > base_end_day:
                        return False

                    return True
            else:
                # base_period是时间点
                base_month, base_day = self._extract_date_parts(base_period)

                # 判断user_period是时间段还是时间点
                if '-' in user_period:
                    # user_period是时间段，base_period是时间点
                    # 这种情况下，user_period必须完全在base_period之前
                    user_start_str, user_end_str = user_period.split('-')
                    user_end_month, user_end_day = self._extract_date_parts(user_end_str)

                    # 检查user_period的结束时间是否不晚于base_period
                    if user_end_month < base_month:
                        return True
                    elif user_end_month == base_month:
                        return user_end_day <= base_day
                    else:
                        return False
                else:
                    # 两者都是时间点，直接比较
                    user_month, user_day = self._extract_date_parts(user_period)

                    if user_month < base_month:
                        return True
                    elif user_month == base_month:
                        return user_day <= base_day
                    else:
                        return False

        except Exception as e:
            logger.warning(f"比较推广周期日期时发生错误: {e}")
            return True  # 出错时默认返回True，避免误判

    def _build_promotion_extraction_prompt(self, base_info: str, user_info: str) -> str:
        """
        构建推广周期提取提示词

        :param base_info: 基础表单信息
        :param user_info: 用户表单信息
        :return: 构建的提示词
        """
        return f"""
你是一个专业的推广周期时间提取专家，请你提取base_info与user_info中推广日期的时间。

基础表单(base_info):
{base_info}

用户表单(user_info):
{user_info}

请按照以下要求提取推广周期：
1. 提取base_info和user_info中推广周期字段的时间
2. 将时间统一转换为"月.日-月.日"或"月.日"的格式
3. 如果是时间段，如"10月2日到10月4日"，转换为"10.2-10.4"
4. 如果是单个时间点，如"11月12日前发布"，转换为"11.12"
5. 只返回提取后的时间格式，不要其他内容

请以JSON格式返回：
{{
  "base_period": "提取的base_info推广周期",
  "user_period": "提取的user_info推广周期"
}}
"""

    def _parse_promotion_response(self, response: str) -> Tuple[Optional[str], Optional[str]]:
        """
        解析大模型返回的推广周期响应

        :param response: 大模型响应
        :return: (base_period, user_period)
        """
        try:
            # 清理响应文本，提取JSON部分
            response = response.strip()
            # 移除可能的代码块标记
            if response.startswith('```json'):
                response = response[7:]
            if response.endswith('```'):
                response = response[:-3]

            data = json.loads(response)
            base_period = data.get("base_period")
            user_period = data.get("user_period")
            return base_period, user_period
        except Exception as e:
            logger.error(f"解析推广周期响应失败: {e}, 响应内容: {response}")
            return None, None

    async def check_promotion_period(self, base_info: str, user_info: str) -> Optional[str]:
        """
        检查推广周期是否一致

        :param base_info: 基础表单信息
        :param user_info: 用户表单信息
        :return: 如果不一致返回差异描述，否则返回None
        """
        try:
            # 构建推广周期提取提示词
            prompt = self._build_promotion_extraction_prompt(base_info, user_info)
            logger.info("构建推广周期提取提示词完成")

            # 调用大模型提取推广周期
            response = await self.doubao_client.generate_text(prompt)
            logger.info(f"推广周期提取结果: {response}")

            # 解析响应，提取base和user的推广周期
            base_period, user_period = self._parse_promotion_response(response)

            if not base_period or not user_period:
                logger.warning("无法提取推广周期，跳过推广周期检查")
                return None

            logger.info(f"提取的base推广周期: {base_period}")
            logger.info(f"提取的user推广周期: {user_period}")

            # 比较推广周期
            if not self._compare_promotion_dates(base_period, user_period):
                logger.info("推广周期不一致")
                return f"档期不满足：推广周期不一致，基础值：{base_period}，用户值：{user_period}"

            logger.info("推广周期一致")
            return None

        except Exception as e:
            logger.error(f"推广周期检查失败: {str(e)}")
            return None

    def _extract_creation_direction(self, text: str) -> Optional[str]:
        """
        从文本中提取创作方向

        :param text: 输入文本
        :return: 提取到的创作方向，如"种草"、"测评"等
        """
        try:
            # 定义创作方向关键词
            direction_keywords = {
                '种草': ['种草', '产品推荐', '好物分享', '购物分享', '使用感受'],
                '测评': ['测评', '评测', '产品评测', '使用评测', '深度评测'],
                '教程': ['教程', '教学', '指南', '使用教程', '操作指南'],
                '开箱': ['开箱', '拆箱', '开箱体验'],
                '体验': ['体验', '使用体验', '亲身感受']
            }

            # 查找创作方向关键词
            found_directions = []

            # 先尝试精确匹配"创作方向："字段
            direction_pattern = r'创作方向[：:\s]*([^\n\r]+)'
            direction_match = re.search(direction_pattern, text)
            if direction_match:
                direction_text = direction_match.group(1).strip()
                for main_direction, keywords in direction_keywords.items():
                    for keyword in keywords:
                        if keyword in direction_text:
                            found_directions.append(main_direction)
                            break

            # 如果没有找到，在整个文本中搜索关键词
            if not found_directions:
                for main_direction, keywords in direction_keywords.items():
                    for keyword in keywords:
                        if keyword in text:
                            found_directions.append(main_direction)
                            break

            # 返回找到的第一个创作方向，或者None
            return found_directions[0] if found_directions else None

        except Exception as e:
            logger.warning(f"提取创作方向时发生错误: {e}")
            return None

    def _compare_creation_directions(self, base_direction: str, user_direction: str) -> bool:
        """
        比较创作方向是否匹配

        :param base_direction: 基础创作方向
        :param user_direction: 用户创作方向
        :return: 是否匹配
        """
        try:
            # 如果任一方向为空，返回True（跳过检查）
            if not base_direction or not user_direction:
                return True

            # 定义创作方向的匹配关系
            direction_groups = {
                '种草': ['种草', '教程', '开箱', '体验'],
                '测评': ['测评', '体验'],
                '教程': ['种草', '教程'],
                '开箱': ['种草', '开箱'],
                '体验': ['种草', '测评', '体验']
            }

            # 检查user_direction是否在base_direction的匹配组中
            base_group = direction_groups.get(base_direction, [])
            return user_direction in base_group

        except Exception as e:
            logger.warning(f"比较创作方向时发生错误: {e}")
            return True

    async def check_creation_direction(self, base_info: str, user_info: str) -> Optional[str]:
        """
        检查创作方向是否一致

        :param base_info: 基础表单信息
        :param user_info: 用户表单信息
        :return: 如果不一致返回差异描述，否则返回None
        """
        try:
            # 提取基础创作方向
            base_direction = self._extract_creation_direction(base_info)
            # 提取用户创作方向
            user_direction = self._extract_creation_direction(user_info)

            logger.info(f"提取的base创作方向: {base_direction}")
            logger.info(f"提取的user创作方向: {user_direction}")

            # 如果任一方向为空，跳过检查
            if not base_direction or not user_direction:
                logger.warning("无法提取创作方向，跳过创作方向检查")
                return None

            # 比较创作方向
            if not self._compare_creation_directions(base_direction, user_direction):
                logger.info("创作方向不一致")
                return f"创作风格不符：创作方向不一致，基础值：{base_direction}，用户值：{user_direction}"

            logger.info("创作方向一致")
            return None

        except Exception as e:
            logger.error(f"创作方向检查失败: {str(e)}")
            return None